/** 事件管理
 * 注意：target dom中有evenType属性才生效
 * 说明：
 *    1.鼠标从 按下---移动---放开 过程中为一条过程。
 *    2.每次过程中会暴露钩子（需要子类重写方法）
 *    3.提供销毁事件方法（外部切换工具时需主动调用）
 *  homeEl - 监听容器
 *  maxX | maxY - 容器大小
 *  pageX | pageY - 容器距离页面位置（用于计算内部相对位置）
 *  beginX | beginY - 记录点过程起始坐标（用于后续移动操作的计算）
 *  lastX | lastY - 上一次鼠标停留位置（过程中）
 * 控制器使用方法：
 *    1.readyTool激活时调用
 *    2.stopTool暂停时调用
 * 子类方法：参数为当前鼠标x,y
 *    1.onBegin:（过程）按下时的钩子
 *    2.onMove:（过程）移动时的钩子
 *    2.onEnd: （过程）放开鼠标时的钩子
 *    4.onMousemoveFromHome：独立的鼠标移动钩子
 * 内部工具：
 *    1.页面坐标转内部相对坐标
 * */
// https://www.cnblogs.com/lichunlin/p/3673329.html
import {EVENT_TYPES} from "./var";
import {Base} from './base';
export class EventManager extends Base{
  constructor(option) {
    super(option);
    // todo ie不支持
    if (EventManager === new.target) {
      throw new Error('抽象类（EventManager）不能被实例化');
    }
    // 3.初始化事件
    this.initEvent();
    // 4.开始监听
    this.startEvent();
  }

  // 初始化事件
  initEvent() {
    /** （鼠标按下后）移动时出发*/
    this.mousedownAndmoveFun = ({pageX, pageY}) => {
      this.readSize();
      const to = this.checkXYOffset({
        x: pageX, y: pageY
      });
      // 1.计算实际位置
      // 计算上一次位置
      const from = {
        x: this.lastX, y: this.lastY
      };

      // 2.发送事件
      this.onMove(from, to);
      // 3.更新坐标
      this.lastX = to.x;
      this.lastY = to.y;
    };
    /** 鼠标按下时触发 */
    this.mousedownFun = event => {
      const {pageX, pageY, target, button} = event;
      this.readSize();
      this.activetargetEventType = target.getAttribute('eventType');
      if (!this.activetargetEventType) {
        return;
      }
      // 2.记录当前位置
      const point = this.checkXYOffset({
        x: pageX, y: pageY
      });
      this.beginX = point.x;
      this.beginY = point.y;
      // 3.发送事件
      this.onBegin(point, event);
      // 4.更新坐标
      this.lastX = this.beginX;
      this.lastY = this.beginY;
      // 5.注册事件
      window.addEventListener('mousemove', this.mousedownAndmoveFun);
      window.addEventListener('mouseup', this.mouseupFun);
    };
    /** 鼠标松开时触发 */
    this.mouseupFun = ({pageX, pageY, target, button}) => {
      this.readSize();
      window.removeEventListener('mousemove', this.mousedownAndmoveFun);
      window.removeEventListener('mouseup', this.mouseupFun);
      const point = this.checkXYOffset({
        x: pageX, y: pageY
      });
      this.onEnd(point);
    };
    this.mousemoveFun = ({pageX, pageY, target}) => {
      this.readSize();
      const activetargetEventType = target.getAttribute('eventType');
      if (activetargetEventType !== EVENT_TYPES.darwerEvenType) {
        return;
      } else {
        const point = this.checkXYOffset({
          x: pageX, y: pageY
        });
        this.onMousemoveFromHome(point);
      }
    };
    /** 键盘事件 */
    this.readImgFun = (e) => {
      console.log('readImgFun');
      setTimeout(_ => {
        const img = this.readClipbrdInput.querySelector('img');
        if (img) {
          img.style = {};
          this.onClipbrdEvent('paste', img);
        }
        this.readClipbrdInput.innerHTML = '';
      }, 200);
    };
    this.keyupFun = (e) => {
      // 清空上一次事件记录
      this.lastKeyCode = '';
    };
    this.keydownFun = (e) => {
      // 1.获取事件信息
      const {ctrlKey, shiftKey, altKey, keyCode, target} = e;
      // 焦点不在当前事件托管中（编辑框）
      const notEventHome = target.getAttribute('data-draw-role') !== 'EventHome';
      // 重复事件
      const isRepeat = this.lastKeyCode === keyCode;
      // 暂不支持的事件
      const notUse = shiftKey || altKey;
      // 2.判断是否重复事件
      if (notEventHome || isRepeat || notUse) {
        return;
      } else {
        this.lastKeyCode = keyCode;
        // 4.命令处理
        if (ctrlKey) {
          switch (keyCode) {
            case 88: // 剪切
              this.onClipbrdEvent('cut');
              break;
            case 67: //复制
              this.onClipbrdEvent('copy');
              break;
            case 86: // 粘贴
              this.readyCopy();
              break;
          }
        }
      }
    };
  }

  /** 事件状态 */
  // 选择工具时
  startEvent() {
    // 鼠标事件
    this.box.addEventListener('mousedown', this.mousedownFun);
    this.box.addEventListener('mousemove', this.mousemoveFun);
    // 键盘事件
    this.box.addEventListener('keydown', this.keydownFun);
    // 剪贴板事件
    this.box.addEventListener('keyup', this.keyupFun);
    this.box.addEventListener('paste', this.readImgFun);
  }

  // 停用该工具时调用
  stopEvent() {
    this.endFun();
    this.homeEl.removeEventListener('mousedown', this.mousedownFun);
  }

  /** 可重写 */
  // 路径完成时调用：清空移动、放开鼠标事件
  onEnd() {
    this.lastX = this.lastY = undefined;
  }

  onMove() {
  }

  onBegin() {
  }

  onMousemoveFromHome() {
  }
  // 剪贴板操作事件
  onClipbrdEvent(type, e={}) {
  }

  /** 工具 */
  // 矫正操作坐标
  checkXYOffset({x, y}) {
    x -= this.pageX;
    y -= this.pageY;
    x = Math.max(0, x);
    x = Math.min(x, this.maxX);
    y = Math.max(0, y);
    y = Math.min(y, this.maxY);
    return isNaN(x) || isNaN(y) ? null : {x, y};
  }
  readyCopy() {
    if (this.option.clipbrdType === 'out') {
      this.readClipbrd();
    } else {
      this.onClipbrdEvent('paste', this.vClipbrd);
    }
  }
  // 读取剪贴板内容
  readClipbrd() {
    let input = this.readClipbrdInput;
    if (!input) {
      this.readClipbrdInput = input = document.createElement('div');
      this.readClipbrdInput.setAttribute('contenteditable', "true");
      input.classList.add('draw-readclipbrdImg');
      // 防止输入干扰
      input.addEventListener('keydown', (e) => {
        e.preventDefault();
      });
      this.homeEl.appendChild(input);
    }
    input.innerHTML='';
    input.focus();
    document.execCommand('paste');
  }
}